---
description:
  Learn how to set up GraphQL subscriptions to receive real-time notifications from the server,
  using the GraphQL subscription type.
---

import { Callout } from '@theguild/components';

# Subscriptions

In addition to fetching data using queries and modifying data using mutations, the GraphQL spec
supports a third operation type, called `subscription`.

GraphQL's subscriptions are a way to push data from the server to the clients that choose to listen
to real time messages from the server. Subscriptions are similar to queries in that they specify a
set of fields to be delivered to the client, but instead of immediately returning a single answer, a
result is sent every time a particular event happens on the server.

A common use case for subscriptions is notifying the client side about particular events, for
example the creation of a new object, updated fields and so on.

## Overview

GraphQL subscriptions have to be defined in the schema, just like queries and mutations:

```typescript
type Subscription {
  commentAdded(repoFullName: String!): Comment
}
```

On the client, subscription queries look just like any other kind of operation:

```graphql
subscription onCommentAdded($repoFullName: String!) {
  commentAdded(repoFullName: $repoFullName) {
    id
    content
  }
}
```

The response sent to the client looks as follows:

```typescript
{
  "data": {
    "commentAdded": {
      "id": "123",
      "content": "Hello!"
    }
  }
}
```

In the above example, the server is written to send a new result every time a comment is added on
GitHunt for a specific repository. Note that the code above only defines the GraphQL subscription in
the schema. Read [setting up subscriptions on the client](#client-setup) and
[setting up GraphQL subscriptions for the server](https://www.apollographql.com/docs/graphql-subscriptions)
to learn how to add subscriptions to your app.

### When to Use Subscriptions

In most cases, intermittent polling or manual refetching are actually the best way to keep your
client up to date. So when is a subscription the best option? Subscriptions are especially useful
if:

1. The initial state is large, but the incremental change sets are small. The starting state can be
   fetched with a query and subsequently updated through a subscription.
1. You care about low-latency updates in the case of specific events, for example in the case of a
   chat application where users expect to receive new messages in a matter of seconds.

A future version of Apollo or GraphQL might include support for live queries, which would be a
low-latency way to replace polling, but at this point general live queries in GraphQL are not yet
possible outside of some relatively experimental setups.

## Client Setup

Because subscriptions maintain a persistent connection, they can't use the default HTTP transport
that Apollo Client uses for queries and mutations. Instead, Apollo Client subscriptions most
commonly communicate over WebSocket.

Install the community-maintained [`graphql-ws`](https://github.com/enisdenjo/graphql-ws) library.

```sh
npm install graphql-ws
```

Let's look at how to add support for this transport to Apollo Client.

```ts
import { createClient } from 'graphql-ws';
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';

const ws = new GraphQLWsLink(
  createClient({
    url: 'ws://localhost:3000/graphql',
  }),
);
```

```ts filename="app.config.ts"
import { provideApollo } from 'apollo-angular';
import { HttpLink } from 'apollo-angular/http';
import { Kind, OperationTypeNode } from 'graphql';
import { createClient } from 'graphql-ws';
import { inject } from '@angular/core';
import { InMemoryCache, split } from '@apollo/client';
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
import { getMainDefinition } from '@apollo/client/utilities';

provideApollo(() => {
  const httpLink = inject(HttpLink);
  // Create an http link:
  const http = httpLink.create({
    uri: 'http://localhost:3000/graphql',
  });

  // Create a WebSocket link:
  const ws = new GraphQLWsLink(
    createClient({
      url: 'ws://localhost:3000/graphql',
    }),
  );

  // Using the ability to split links, you can send data to each link
  // depending on what kind of operation is being sent
  const link = split(
    // Split based on operation type
    ({ query }) => {
      const definition = getMainDefinition(query);
      return (
        definition.kind === Kind.OPERATION_DEFINITION &&
        definition.operation === OperationTypeNode.SUBSCRIPTION
      );
    },
    ws,
    http,
  );

  return {
    link,
    cache: new InMemoryCache(),
    // other options...
  };
});
```

Now, queries and mutations will go over HTTP as normal, but subscriptions will be done over the
websocket transport.

With GraphQL subscriptions your client will be alerted on push from the server and you should choose
the pattern that fits your application the most:

- Use it as a notification and run any logic you want when it fires, for example alerting the user
  or refetching data
- Use the data sent along with the notification and merge it directly into the store (existing
  queries are automatically notified)

With `subscribeToMore` and `subscribe`, you can easily do the latter.

## `subscribe`

The `subscribe` is a method available directly in `Apollo` service. It works like `watchQuery` but
it's for GraphQL Subscriptions.

```ts
const COMMENTS_SUBSCRIPTION = gql`
  subscription onCommentAdded($repoFullName: String!){
    commentAdded(repoFullName: $repoFullName){
      id
      content
    }
  }
`;

@Component({ ... })
class CommentsComponent {
  constructor(apollo: Apollo) {
    apollo.subscribe({
      query: COMMENTS_SUBSCRIPTION,
      variables: {
        repoName: `Ecodev/apollo-angular`
      },
      /*
        accepts options like `errorPolicy` and `fetchPolicy`
      */
    }).subscribe((result) => {
      if (result.data?.commentAdded) {
        console.log('New comment:', result.data.commentAdded);
      }
    });
  }
}
```

In the example above, the `CommentsComponent` subscribes to `commentAdded` events and just like in
`watchQuery` gets receives every emitted result.

## `subscribeToMore`

The `subscribeToMore` is a bit different from `subscribe`. It is a method available on every watched
query in `apollo-angular`. It works just like
[`fetchMore`](../caching/interaction#incremental-loading-fetchmore), except that the update function
gets called every time the subscription returns, instead of only once.

Here is a regular query:

```typescript
import { Apollo, gql, QueryRef } from 'apollo-angular';
import { Observable } from 'rxjs';

const COMMENT_QUERY = gql`
  query Comment($repoName: String!) {
    entry(repoFullName: $repoName) {
      comments {
        id
        content
      }
    }
  }
`;

@Component({
  // ...
})
class CommentsComponent {
  commentsQuery: QueryRef<any>;
  comments: Observable<any>;
  params: any;

  constructor(apollo: Apollo) {
    this.commentsQuery = apollo.watchQuery({
      query: COMMENT_QUERY,
      variables: {
        repoName: `${params.org}/${params.repoName}`,
      },
    });

    this.comments = this.commentsQuery.valueChanges; // async results
  }
}
```

Now, let's add the subscription.

Add a function called `subscribeToNewComments` that will subscribe using `subscribeToMore` and
update the query's store with the new data using `updateQuery`.

Note that the `updateQuery` callback must return an object of the same shape as the initial query
data, otherwise the new data won't be merged. Here the new comment is pushed in the `comments` list
of the `entry`:

```ts
const COMMENTS_SUBSCRIPTION = gql`
  subscription onCommentAdded($repoFullName: String!) {
    commentAdded(repoFullName: $repoFullName) {
      id
      content
    }
  }
`;

@Component({
  // ...
})
class CommentsComponent {
  commentsQuery: QueryRef<any>;

  // ... it is the same component as one above

  subscribeToNewComments(params) {
    this.commentsQuery.subscribeToMore({
      document: COMMENTS_SUBSCRIPTION,
      variables: {
        repoName: params.repoFullName,
      },
      updateQuery: (prev, { subscriptionData }) => {
        if (!subscriptionData.data) {
          return prev;
        }

        const newFeedItem = subscriptionData.data.commentAdded;

        return {
          ...prev,
          entry: {
            comments: [newFeedItem, ...prev.entry.comments],
          },
        };
      },
    });
  }
}
```

and start the actual subscription by calling the `subscribeToNewComments` function with the
subscription variables:

```ts
@Component({
  // ...
})
class CommentsComponent {
  // ... same component as one above

  ngOnInit() {
    this.subscribeToNewComments({
      repoFullName: params.repoFullName,
    });
  }
}
```

## `subscribe` vs `subscribeToMore`

In short:

- `subscribe` listens to results emitted by a GraphQL Subscription and lets you update one or many
  queries.
- `subscribeToMore` listens to GraphQL Subscription as well but is tightly connected with one query.

We recommend to use `subscribe` in most cases and leave `subscribeToMore` for things like
pagination.

## Authentication over WebSocket

In many cases it is necessary to authenticate clients before allowing them to receive subscription
results. To do this, the `SubscriptionClient` constructor accepts a `connectionParams` field, which
passes a custom object that the server can use to validate the connection before setting up any
subscriptions.

```ts
import { WebSocketLink } from 'apollo-link-ws';

const wsLink = new WebSocketLink({
  uri: `ws://localhost:5000/graphql`,
  options: {
    reconnect: true,
    connectionParams: {
      authToken: user.authToken,
    },
  },
});
```

<Callout>
  You can use `connectionParams` for anything else you might need, not only authentication, and
  check its payload on the server side with
  [SubscriptionsServer](https://apollographql.com/docs/graphql-subscriptions/authentication).
</Callout>
